using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Input;
using Microsoft.Xna.Framework.GamerServices;

namespace FuncWorks.Xna.Input
{
    // Unknown, but appears to be relevant:
    //
    // Left Thumbstick X is the solo fret bar for GHWT guitars, from 1 (orange) to -0.75 (green).
    // Not sure if there's anything else mapped here, because yellow returns 0--which is the default.

    public class Guitar
    {
        #region Instance Fields
        public PlayerIndex Index { get; private set; }
        public string Name { get; private set; }
        GamePadState lastState;
        public GamePadState State { get; private set; }
        public bool IsAlternateGuitar { get; private set; }

		public GuitarStrumState Red { get; private set; }
		public GuitarStrumState Yellow { get; private set; }
		public GuitarStrumState Blue { get; private set; }
		public GuitarStrumState Orange { get; private set; }
		public GuitarStrumState Green { get; private set; }

		public GuitarStrumState StrumUp { get; private set; }
		public GuitarStrumState StrumDown { get; private set; }

        public double RollAngle { get; private set; }
        public float Tilt { get; private set; }
        public float Whammy { get; private set; }


        #endregion

        #region Static Fields
		public static GuitarCollection ActiveGuitars { get; private set; }
        #endregion

        public Guitar(PlayerIndex playerIndex)
        {
            // Set variables
            Index = playerIndex;
            State = lastState = GamePad.GetState(playerIndex);

            // Get profile information
			if (Gamer.SignedInGamers[playerIndex] != null) { Name = Gamer.SignedInGamers[playerIndex].Gamertag; }
			else
            {
                switch (playerIndex)
                {
                    case PlayerIndex.One: Name = "Player 1"; break;
                    case PlayerIndex.Two: Name = "Player 2"; break;
                    case PlayerIndex.Three: Name = "Player 3"; break;
                    case PlayerIndex.Four: Name = "Player 4"; break;
                    default: Name = ""; break;
                }
            }
        }

        public static Guitar[] Discover()
        {
			if (ActiveGuitars == null) { ActiveGuitars = new GuitarCollection(); }

            List<Guitar> results = new List<Guitar>();

            foreach (PlayerIndex index in new PlayerIndex[] { PlayerIndex.One, PlayerIndex.Two, PlayerIndex.Three, PlayerIndex.Four })
            {
                if (ActiveGuitars.Count(x => x.Index == index) > 0) { continue; }
                GamePadCapabilities caps = GamePad.GetCapabilities(index);
                if (caps.IsConnected && (caps.GamePadType == GamePadType.Guitar || caps.GamePadType == GamePadType.AlternateGuitar))
                {
                    Guitar guitar = new Guitar(index);
                    guitar.IsAlternateGuitar = (caps.GamePadType == GamePadType.AlternateGuitar);
                    ActiveGuitars.Add(guitar);
                    results.Add(guitar);
                }
            }

            return results.ToArray();
        }

		public static Guitar[] Purge()
		{
			Guitar[] results = (from k in ActiveGuitars where !k.State.IsConnected select k).ToArray<Guitar>();
			foreach (Guitar guitar in results) { ActiveGuitars.Remove(guitar); }
			return results;
		}

		GuitarStrumState GetStrumOrFretState(Buttons button)
        {
            if (!lastState.IsButtonDown(button) && State.IsButtonDown(button))
            {
				return GuitarStrumState.Begin;
            }
            else if (lastState.IsButtonDown(button) && State.IsButtonDown(button))
            {
				return GuitarStrumState.Continuing;
            }
            else if (lastState.IsButtonDown(button) && !State.IsButtonDown(button))
            {
				return GuitarStrumState.Ending;
            }
			return GuitarStrumState.None;
        }

        public void Update()
        {
            State = GamePad.GetState(Index);

            if (State.IsConnected)
            {
                if (!IsAlternateGuitar)
                {
					Green = GetStrumOrFretState(Buttons.A);
					Red = GetStrumOrFretState(Buttons.B);
					Yellow = GetStrumOrFretState(Buttons.Y);
					Blue = GetStrumOrFretState(Buttons.X);
					Orange = GetStrumOrFretState(Buttons.LeftShoulder);
					StrumUp = GetStrumOrFretState(Buttons.DPadUp);
					StrumDown = GetStrumOrFretState(Buttons.DPadDown);

					Tilt = State.ThumbSticks.Right.Y;
					Whammy = (State.ThumbSticks.Right.X + 1) / 2.0f;
					RollAngle = 0.0;
                }
                else
                {
                    Green = GetStrumOrFretState(Buttons.A);
                    Red = GetStrumOrFretState(Buttons.B);
                    Yellow = GetStrumOrFretState(Buttons.Y);
                    Blue = GetStrumOrFretState(Buttons.X);
                    Orange = GetStrumOrFretState(Buttons.LeftShoulder);
                    StrumUp = GetStrumOrFretState(Buttons.DPadUp);
                    StrumDown = GetStrumOrFretState(Buttons.DPadDown);

                    Tilt = State.ThumbSticks.Right.Y;
                    Whammy = (State.ThumbSticks.Right.X + 1) / 2.0f;

                    // http://forums.xna.com/forums/p/1001/5508.aspx#5508
                    RollAngle = Math.Atan2(State.Triggers.Left - 0.5f, State.Triggers.Right - 0.5f);
                }
            }
            else
            {
				Green = Red = Yellow = Blue = Orange = StrumUp = StrumDown = GuitarStrumState.None;
                Tilt = Whammy = 0f;
                RollAngle = 0.0;                
            }

            lastState = State;
        }
    }
}
